#include "GraphObject.h"
#include "GraphDisplay.h"

using namespace GUI;

static GUI::Rect sNullRect = {0, 0, 0, 0};

GraphObject::GraphObject(GraphDisplay& display, float zorder)
	:mDisplay(display),
	 mVisible(true),
	 mRectSet(false),
	 mZOrder(zorder),
	 mAspectRatioMode(AspectRatioMode::AdjustNone)
{
	mObjectRect = sNullRect;
	mBoundingRect = sNullRect;
	mDisplay.Add(this);
	Invalidate();
}

GraphObject::~GraphObject()
{
	Invalidate();
	mDisplay.Remove(this);
}

GraphObject& GraphObject::Invalidate()
{
	mDisplay.InvalidateRect(mBoundingRect);
	return *this;
}

GraphObject& GraphObject::SetObjectRect(const GUI::Rect& inRect)
{
	if(mObjectRect != inRect)
	{
		int changedFlags = Position;
		bool resized = mObjectRect.Width() != inRect.Width() || mObjectRect.Height() != inRect.Height();
		if(resized)
			changedFlags |= Size;

		Invalidate();
		mObjectRect = inRect;
		mBoundingRect = mDisplay.NormalizedToPixelCoords(inRect);
		mRectSet = true;
		Change(changedFlags);
	}

	return *this;
}

GUI::Rect GraphObject::BoundingRect() const
{
	return mDisplay.PixelToNormalizedCoords(mBoundingRect);
}

void GraphObject::Paint()
{
	if(mRectSet && mVisible)
	{
		DrawContext dc = 
		{
			mDisplay.mContext.handle,
			{0, 0, 0,0}
		};
		dc.rect = mBoundingRect;
		OnPaint(dc);
	}
}

void GraphObject::Change(int which)
{
	if(mRectSet)
	{
		Invalidate();
		DrawContext dc = 
		{
			mDisplay.mContext.handle,
			{0,0,0,0}
		};
		dc.rect = mDisplay.NormalizedToPixelCoords(mObjectRect);

		int considered = 0;

		if(which & Position)
			OnMove(dc);
		considered |= Position;

		if(which & Size)
			OnResize(dc);
		considered |= Size;

		if(which & ~considered)
			OnChange(dc);

		mBoundingRect = dc.rect;
		Invalidate();
	}
}

bool GraphObject::Click(const Point& p)
{
	Rect r = mDisplay.PixelToNormalizedCoords( mBoundingRect );
	return PointInRect( p, r ) && OnClick( p );
}